from fastapi import APIRouter, Depends, Request, HTTPException, status, Query
from novelapp.config.database import connect
from novelapp.models.models import LkBookList, LkBookListBook
from novelapp.common.common import returnData, setLog
from typing import Optional
import aiohttp
import asyncio
import random
import json
import re
from datetime import datetime
from mongoengine.queryset.visitor import Q

router = APIRouter()

# 设置日志
logger = setLog('lkbooklist.log')

# 常见的浏览器用户代理列表
user_agents = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15",
]

# Cookie值 (需要定期更新)
cookies_value = "EGG_SESS=qIOxTFmy7ETN9HKDjjgn5RN-SUjM7N7nRTCgRfiyyt-CkrKs6OiOuBOk_FeWy-Y2JuYxQtMfzOzg0gKFjCuPDqwsjeP0pzekb3DYJpy32715ucb1BOuHl5JuU8rrqcP_jedKi_LLyV3kzX408BPmPGXiPXd7HwlLgYmCvyIwwPWu7hyVGsz-u3_5GTWVDc2p"


async def fetch_lk_booklists_from_api(page: int = 1, page_size: int = 20, sort_order: str = "DEFAULT", category: Optional[str] = None):
    """
    从龙空API获取书单列表
    
    Args:
        page: 页码
        page_size: 每页数量
        sort_order: 排序方式 (DEFAULT, HOT, NEW等)
        category: 分类
        
    Returns:
        tuple: (书单列表, 是否有更多, 总数)
    """
    url = "https://api.lkong.com/api"
    
    # 构建GraphQL请求payload
    payload = {
        "operationName": "GetBookLists",
        "variables": {
            "page": page,
            "pageSize": page_size,
            "sortOrder": sort_order
        },
        "query": """query GetBookLists($page: Int, $pageSize: Int, $sortOrder: BookListSortOrder, $category: String) {
  getBookLists(
    page: $page
    pageSize: $pageSize
    sortOrder: $sortOrder
    category: $category
  ) {
    data {
      listId
      title
      description
      category
      bookCount
      viewCount
      favoritedCount
      createdAt
      lastActiveAt
      author {
        uid
        name
        avatar
        __typename
      }
      isFavorited
      avatar
      __typename
    }
    hasMore
    total
    __typename
  }
}"""
    }
    
    # 如果有分类参数，添加到variables中
    if category:
        payload["variables"]["category"] = category
    
    # 随机选择用户代理和添加随机头部信息
    headers = {
        "User-Agent": random.choice(user_agents),
        "Accept-Language": random.choice(["en-US", "en-GB", "zh-CN"]),
        "Content-Type": "application/json",
        "Cookie": cookies_value
    }
    
    try:
        async with aiohttp.ClientSession() as session:
            async with session.post(url, json=payload, headers=headers, ssl=False) as response:
                response.raise_for_status()
                result = await response.json()
                
                # 解析响应数据
                book_lists_data = result.get('data', {}).get('getBookLists', {})
                data = book_lists_data.get('data', [])
                has_more = book_lists_data.get('hasMore', False)
                total = book_lists_data.get('total', 0)
                
                return data, has_more, total
                
    except aiohttp.ClientError as e:
        logger.error(f"Error fetching book lists from API: {e}")
        return [], False, 0
    except Exception as e:
        logger.error(f"Unexpected error: {e}")
        return [], False, 0


def save_booklists_to_db(book_lists_data: list) -> int:
    """
    保存书单数据到数据库（去重）
    
    Args:
        book_lists_data: 书单数据列表
        
    Returns:
        int: 新增/更新的书单数量
    """
    saved_count = 0
    
    for item in book_lists_data:
        try:
            list_id = item.get('listId')
            if not list_id:
                continue
            
            # 检查是否已存在
            existing = LkBookList.objects(listId=list_id).first()
            
            # 解析时间戳
            created_at = datetime.fromtimestamp(item.get('createdAt', 0) / 1000.0) if item.get('createdAt') else None
            last_active_at = datetime.fromtimestamp(item.get('lastActiveAt', 0) / 1000.0) if item.get('lastActiveAt') else None
            
            # 准备数据
            author_info = item.get('author', {})
            avatars_raw = item.get('avatar', [])
            # 处理 avatar: 如果是列表则保留,如果是字符串则转为列表,如果是 null 则为空列表
            if isinstance(avatars_raw, list):
                avatars = avatars_raw
            elif isinstance(avatars_raw, str):
                avatars = [avatars_raw]
            else:
                avatars = []
            
            book_list_data = {
                'listId': str(list_id),  # 确保转为字符串
                'title': item.get('title', ''),
                'description': item.get('description', ''),
                'category': item.get('category', ''),
                'bookCount': item.get('bookCount', 0),
                'viewCount': item.get('viewCount', 0),
                'favoritedCount': item.get('favoritedCount', 0),
                'author_uid': author_info.get('uid'),
                'author_name': author_info.get('name', ''),
                'author_avatar': author_info.get('avatar') or '',  # null 时转为空字符串
                'avatars': avatars,  # 列表格式
                'isFavorited': 1 if item.get('isFavorited') else 0,
                'createdAt': created_at,
                'lastActiveAt': last_active_at,
                'lastUpdated': datetime.now()
            }
            
            if existing:
                # 更新现有记录
                for key, value in book_list_data.items():
                    setattr(existing, key, value)
                existing.save()
            else:
                # 创建新记录
                new_list = LkBookList(**book_list_data)
                new_list.save()
            
            saved_count += 1
            
        except Exception as e:
            logger.error(f"Error saving book list {item.get('listId')}: {e}")
            continue
    
    return saved_count


@router.get("/get_list/")
async def get_lk_booklist(
    page: int = Query(1, gt=0, description="页码"),
    page_size: int = Query(20, gt=0, le=100, description="每页数量"),
    sort_order: str = Query("DEFAULT", description="排序方式: DEFAULT, HOT, NEW"),
    category: Optional[str] = Query(None, description="分类筛选: male/female"),
    keyword: Optional[str] = Query(None, description="搜索关键词（同时搜索标题和作者）"),
    from_api: bool = Query(False, description="是否从API实时获取")
):
    """
    获取龙空书单列表
    
    参数:
        - page: 页码，从1开始
        - page_size: 每页数量，最大100
        - sort_order: 排序方式 (DEFAULT/HOT/NEW)
        - category: 分类筛选
        - from_api: 是否从API实时获取（True）还是从数据库查询（False）
    """
    
    if from_api:
        # 从API获取数据
        logger.info(f"Fetching book lists from API - page: {page}, sort: {sort_order}")
        
        # 随机延迟，防止被封
        await asyncio.sleep(random.uniform(0.1, 0.5))
        
        book_lists_data, has_more, total = await fetch_lk_booklists_from_api(
            page=page, 
            page_size=page_size, 
            sort_order=sort_order,
            category=category
        )
        
        if not book_lists_data:
            return returnData(404, '暂无数据', {
                "page": page,
                "page_size": page_size,
                "total": 0,
                "hasMore": False,
                "book_lists": []
            })
        
        # 保存到数据库
        saved_count = save_booklists_to_db(book_lists_data)
        logger.info(f"Saved {saved_count} book lists to database")
        
        return returnData(200, '查询成功', {
            "page": page,
            "page_size": page_size,
            "total": total,
            "hasMore": has_more,
            "saved_count": saved_count,
            "book_lists": book_lists_data
        })
    
    else:
        # 从数据库查询
        logger.info(f"Querying book lists from database - page: {page}")
        
        # 组合查询条件（支持分类/关键词模糊搜索）
        q = Q()
        
        # 分类筛选（AND逻辑）
        if category:
            q &= Q(category=category)
        
        # 关键词搜索（OR逻辑）- 同时搜索标题和作者名
        if keyword:
            search_q = Q(title__icontains=keyword) | Q(author_name__icontains=keyword)
            q &= search_q
        
        # 根据sort_order排序
        sort_field = '-lastActiveAt'  # 默认按活跃时间
        if sort_order == 'HOT':
            sort_field = '-viewCount'
        elif sort_order == 'NEW':
            sort_field = '-createdAt'
        
        # 分页查询
        skip = (page - 1) * page_size
        book_lists_qs = LkBookList.objects(q) if any([category, keyword]) else LkBookList.objects()
        book_lists = book_lists_qs.order_by(sort_field).skip(skip).limit(page_size)
        total_count = book_lists_qs.count()
        
        # 转换为字典列表
        book_lists_data = [bl.get_lklist_info() for bl in book_lists]
        
        logger.info(f"Query result: total={total_count}, page={page}, returned={len(book_lists_data)}")
        
        return returnData(200, '查询成功', {
            "page": page,
            "page_size": page_size,
            "total": total_count,
            "hasMore": skip + page_size < total_count,
            "book_lists": book_lists_data
        })


@router.post("/sync_from_api/")
async def sync_booklists_from_api(
    start_page: int = Query(1, gt=0, description="起始页码"),
    end_page: int = Query(10, gt=0, le=100, description="结束页码"),
    sort_order: str = Query("DEFAULT", description="排序方式")
):
    """
    批量同步龙空书单数据到本地数据库
    
    参数:
        - start_page: 起始页码 (例如: 1)
        - end_page: 结束页码 (例如: 10, 就是请求 1-10 页)
        - sort_order: 排序方式 (DEFAULT/HOT/NEW)
    """
    # 校验参数
    if end_page < start_page:
        return returnData(400, '结束页不能小于起始页', None)
    
    total_saved = 0
    total_pages = end_page - start_page + 1
    
    for page in range(start_page, end_page + 1):
        logger.info(f"Syncing page {page}/{end_page} (total: {total_pages})")
        
        # 随机延迟，防止被封
        await asyncio.sleep(random.uniform(1, 3))
        
        book_lists_data, has_more, total = await fetch_lk_booklists_from_api(
            page=page,
            page_size=20,
            sort_order=sort_order
        )
        
        if not book_lists_data:
            break
        
        print(book_lists_data)
        # quit()
        saved_count = save_booklists_to_db(book_lists_data)
        total_saved += saved_count
        
        logger.info(f"Page {page}: saved {saved_count} book lists")
        
        if not has_more:
            break
    
    return returnData(200, '同步完成', {
        "synced_pages": page,
        "total_saved": total_saved
    })


@router.get("/get_detail/{list_id}/")
async def get_lk_booklist_detail(list_id: str):
    """
    获取书单基本信息
    
    参数:
        - list_id: 书单ID (字符串格式)
        
    功能:
        - 判断书单是否超过3天未更新
        - 若超过3天，从 API 更新书单信息和书籍数据
    """
    book_list = LkBookList.objects(listId=list_id).first()
    
    if not book_list:
        return returnData(404, '书单不存在', None)
    
    # 判断是否需要更新（超过3天或从未同步）
    now = datetime.now()
    needs_update = False
    
    if not book_list.booksLastSyncAt:
        # 从未同步过
        needs_update = True
        logger.info(f"书单 {list_id} 从未同步过，需要更新")
    else:
        # 检查是否超过3天
        days_since_sync = (now - book_list.booksLastSyncAt).days
        if days_since_sync >= 3:
            needs_update = True
            logger.info(f"书单 {list_id} 已 {days_since_sync} 天未更新，需要更新")
    
    # 如果需要更新，从 API 获取最新数据
    if needs_update:
        logger.info(f"开始更新书单 {list_id} 的信息和书籍...")
        
        try:
            # 1. 获取第一页数据，同时获取书单最新信息
            books_data, total_book_count, booklist_info = await fetch_booklist_books_from_api(list_id, 1)
            
            # 处理 None 值
            if books_data is None:
                books_data = []
            if total_book_count is None or total_book_count == 0:
                # 如果API没有返回total_book_count，使用数据库中的bookCount
                total_book_count = book_list.bookCount if book_list.bookCount else 0
                logger.warning(f"API未返回总数，使用数据库中的值: {total_book_count}")
            
            logger.info(f"第一页获取结果: 书籍数={len(books_data)}, 总数={total_book_count}")
            
            if len(books_data) == 0 and total_book_count == 0:
                logger.warning(f"无法从 API 获取书单 {list_id} 的数据")
                # 返回现有数据
                return returnData(200, '查询成功', book_list.get_lklist_info())
            
            # 2. 更新书单基本信息（从 API 返回的 booklist 信息中获取）
            if booklist_info:
                book_list.bookCount = booklist_info.get('bookCount', book_list.bookCount)
                book_list.viewCount = booklist_info.get('viewCount', book_list.viewCount)
                book_list.favoritedCount = booklist_info.get('favoritedCount', book_list.favoritedCount)
                
                # 更新书单标题和描述（如果有变化）
                if booklist_info.get('title'):
                    book_list.title = booklist_info.get('title')
                if booklist_info.get('description'):
                    book_list.description = booklist_info.get('description')
                
                # 更新封面图
                avatars = booklist_info.get('avatar', [])
                if isinstance(avatars, list):
                    book_list.avatars = avatars
                elif isinstance(avatars, str):
                    book_list.avatars = [avatars]
                
                logger.info(f"更新书单信息: bookCount={book_list.bookCount}, viewCount={book_list.viewCount}, favoritedCount={book_list.favoritedCount}")
            
            # 3. 分页获取所有书籍
            all_books_saved = 0
            page = 1
            page_size = 20
            fetched_count = 0
            
            logger.info(f"开始分页获取书籍，总数: {total_book_count}")
            
            # 先处理第一页数据（已经获取）
            if books_data and len(books_data) > 0:
                logger.info(f"  第 {page} 页原始数据数: {len(books_data)}")
                saved_count = save_booklist_books_to_db(list_id, books_data)
                all_books_saved += saved_count
                fetched_count += len(books_data)
                logger.info(f"  第 {page} 页: 获取 {len(books_data)} 本，入库 {saved_count} 本，总计 {fetched_count}/{total_book_count}")
            else:
                logger.warning(f"  第 {page} 页数据为空")
            
            # 继续获取后续页
            while fetched_count < total_book_count:
                page += 1
                logger.info(f"  准备获取第 {page} 页...")
                
                # 随机延迟
                await asyncio.sleep(random.uniform(1, 2))
                
                # 获取下一页
                books_data, _, _ = await fetch_booklist_books_from_api(list_id, page)
                
                # 处理 None 值
                if books_data is None:
                    books_data = []
                
                logger.info(f"  第 {page} 页API返回数据数: {len(books_data)}")
                
                if len(books_data) == 0:
                    logger.info(f"  第 {page} 页没有数据，结束获取")
                    break
                
                # 入库
                saved_count = save_booklist_books_to_db(list_id, books_data)
                all_books_saved += saved_count
                fetched_count += len(books_data)
                logger.info(f"  第 {page} 页: 获取 {len(books_data)} 本，入库 {saved_count} 本，总计 {fetched_count}/{total_book_count}")
                
                # 如果本页数据不足，说明已经是最后一页
                if len(books_data) < page_size:
                    logger.info(f"  本页数据不足 {page_size} 条，已是最后一页")
                    break
                
                # 防止无限循环，最多获取100页
                if page >= 100:
                    logger.warning(f"  已达到最大页数100，停止获取")
                    break
            
            # 4. 更新同步时间
            book_list.booksLastSyncAt = now
            book_list.lastUpdated = now
            book_list.save()
            
            logger.info(f"书单 {list_id} 更新完成: 共入库 {all_books_saved} 本书")
            
        except Exception as e:
            logger.error(f"更新书单 {list_id} 失败: {str(e)}")
            # 失败也返回现有数据
    
    return returnData(200, '查询成功', book_list.get_lklist_info())


async def fetch_booklist_books_from_api(list_id: str, page: int = 1):
    """
    从龙空API获取书单的详细书籍信息(支持分页)
    
    Args:
        list_id: 书单ID
        page: 页码 (默认为1)
        
    Returns:
        tuple: (reviews列表, total_count总数, booklist_info书单信息)
    """
    url = f"https://www.lkong.com/_next/data/N2pf6rU0qGg-_UioUBl6t/booklist/{list_id}.json"
    
    params = {"listId": list_id}
    # 总是添加page参数，包括第1页
    if page > 1:
        params["page"] = page
    
    logger.info(f"请求龙空API: list_id={list_id}, page={page}, params={params}")
    
    # 随机选择用户代理
    headers = {
        "User-Agent": random.choice(user_agents),
        "Accept-Language": random.choice(["en-US", "en-GB", "zh-CN"]),
        "Cookie": cookies_value
    }
    
    try:
        async with aiohttp.ClientSession() as session:
            async with session.get(url, params=params, headers=headers, ssl=False) as response:
                response.raise_for_status()
                result = await response.json()
                
                # 检查是否需要登录
                if result.get('pageProps', {}).get('error'):
                    error_msg = result['pageProps']['error']
                    logger.error(f"API 错误 (list: {list_id}, page: {page}): {error_msg}")
                    return [], 0, None
                
                # 获取书籍列表和总数
                page_props = result.get('pageProps', {})
                reviews = page_props.get('reviews', [])
                
                # 从 booklist 中获取书单信息
                booklist_info = page_props.get('booklist', {})
                total_book_count = booklist_info.get('bookCount', 0)
                
                logger.info(f"API返回: reviews数={len(reviews)}, booklist_info.bookCount={total_book_count}")
                
                return reviews, total_book_count, booklist_info
                
    except aiohttp.ClientError as e:
        logger.error(f"Error fetching booklist books from API (list: {list_id}, page: {page}): {e}")
        return [], 0, None
    except Exception as e:
        logger.error(f"Unexpected error (list: {list_id}, page: {page}): {e}")
        return [], 0, None


def parse_content_text(content_json_str: str) -> str:
    """
    从 content JSON 字符串中解析出纯文本
    
    Args:
        content_json_str: content 字段的 JSON 字符串
        
    Returns:
        str: 解析后的纯文本1
    """
    try:
        content_list = json.loads(content_json_str)
        texts = []
        
        for paragraph in content_list:
            if paragraph.get('type') == 'paragraph':
                children = paragraph.get('children', [])
                for child in children:
                    text = child.get('text', '')
                    if text:
                        texts.append(text)
        
        return ''.join(texts)
    except:
        return content_json_str


def save_booklist_books_to_db(list_id: str, books_data: list) -> int:
    """
    保存书单书籍数据到数据库
    
    Args:
        list_id: 书单ID
        books_data: 书籍数据列表
        
    Returns:
        int: 保存成功的数量
    """
    saved_count = 0
    skipped_count = 0
    
    for idx, item in enumerate(books_data):
        try:
            # 防止 item 为 None
            if item is None:
                logger.warning(f"  跳过第 {idx+1} 条: item 为 None")
                skipped_count += 1
                continue
                
            rid = item.get('rid')
            bid = item.get('bid')
            
            if not rid or not bid:
                book_title = item.get('book', {}).get('title', 'Unknown') if isinstance(item.get('book'), dict) else 'Unknown'
                logger.warning(f"  跳过第 {idx+1} 条: rid={rid}, bid={bid}, 书名={book_title}")
                skipped_count += 1
                continue
            
            # 检查是否已存在
            existing = LkBookListBook.objects(listId=list_id, bid=bid).first()
            
            # 解析评论内容
            content_data = item.get('content')
            if content_data and isinstance(content_data, dict):
                content_json = content_data.get('content', '')
                content_text = parse_content_text(content_json)
            else:
                content_text = ''
            
            # 解析时间戳
            dateline = datetime.fromtimestamp(item.get('dateline', 0) / 1000.0) if item.get('dateline') else None
            lastpost = datetime.fromtimestamp(item.get('lastpost', 0) / 1000.0) if item.get('lastpost') else None
            added_at = datetime.fromtimestamp(item.get('addedAt', 0) / 1000.0) if item.get('addedAt') else None
            
            # 书籍信息（防止 None）
            book_info = item.get('book')
            if not isinstance(book_info, dict):
                book_info = {}
            
            # 书籍统计信息（防止 None）
            book_count = item.get('bookCount')
            if not isinstance(book_count, dict):
                book_count = {}
            
            book_data = {
                'listId': list_id,
                'rid': rid,
                'bid': bid,
                'score': item.get('score', 0),
                'myRate': item.get('myRate', 0),
                'content_text': content_text,
                'dateline': dateline,
                'lastpost': lastpost,
                'replies': item.get('replies', 0),
                'likes': item.get('likes', 0),
                'addedAt': added_at,
                # 书籍信息
                'book_title': book_info.get('title', ''),
                'book_author': book_info.get('author', ''),
                'book_cover': book_info.get('cover', ''),
                'book_wordCount': book_info.get('wordCount', 0),
                'book_finished': 1 if book_info.get('finished') else 0,
                'book_tags': book_info.get('tags', []),
                'book_intro': book_info.get('intro', ''),
                # 书籍统计
                'book_score': book_count.get('score', 0) / 10.0 if book_count.get('score') else 0,  # 转换为 0-10 分
                'book_rateCount': book_count.get('rateCount', 0),
                'book_commentCount': book_count.get('commentCount', 0),
                'book_addListCount': book_count.get('addListCount', 0),
                'lastUpdated': datetime.now()
            }
            
            if existing:
                # 更新现有记录
                for key, value in book_data.items():
                    setattr(existing, key, value)
                existing.save()
            else:
                # 创建新记录
                new_book = LkBookListBook(**book_data)
                new_book.save()
            
            saved_count += 1
            
        except Exception as e:
            # 安全获取 bid
            bid_info = item.get('bid') if item and isinstance(item, dict) else 'unknown'
            logger.error(f"Error saving book {bid_info} for list {list_id}: {e}")
            skipped_count += 1
            continue
    
    if skipped_count > 0:
        logger.warning(f"  本批次共跳过 {skipped_count} 条数据")
    
    return saved_count


@router.get("/get_books/{list_id}/")
async def get_booklist_books(
    list_id: str,
    from_api: bool = Query(False, description="是否从 API 实时获取"),
    page: int = Query(1, gt=0, description="页码"),
    page_size: int = Query(20, gt=0, le=100, description="每页数量")
):
    """
    获取书单中的书籍(支持分页)
    
    参数:
        - list_id: 书单ID
        - from_api: 是否从 API 实时获取 (True) 还是从数据库查询 (False)
        - page: 页码，默认1
        - page_size: 每页数量，默认20
    """
    if from_api:
        # 从 API 获取(自动分页)
        logger.info(f"Fetching books for list {list_id} from API (with pagination)")
        
        all_books = []
        page = 1
        total_saved = 0
        total_book_count = 0
        page_size = 20  # 每页 20 本书
        
        while True:
            # 随机延迟
            await asyncio.sleep(random.uniform(0.5, 1.5))
            
            logger.info(f"Fetching page {page} for list {list_id}")
            books_data, book_count, _ = await fetch_booklist_books_from_api(list_id, page)
            
            # 第一页时获取总书籍数
            if page == 1:
                total_book_count = book_count
                logger.info(f"List {list_id} has {total_book_count} books in total")
            
            if not books_data:
                if page == 1:
                    return returnData(404, '暂无数据或需要登录', {
                        "listId": list_id,
                        "count": 0,
                        "books": []
                    })
                else:
                    break
            
            all_books.extend(books_data)
            
            # 保存到数据库
            saved_count = save_booklist_books_to_db(list_id, books_data)
            total_saved += saved_count
            logger.info(f"Page {page}: saved {saved_count} books")
            
            # 根据已获取数量判断是否还有下一页
            current_fetched = len(all_books)
            if current_fetched >= total_book_count or len(books_data) < page_size:
                logger.info(f"Fetched all books for list {list_id} ({current_fetched}/{total_book_count})")
                break
            
            page += 1
        
        return returnData(200, '查询成功', {
            "listId": list_id,
            "total_pages": page,
            "count": len(all_books),
            "saved_count": total_saved,
            "books": all_books
        })
    
    else:
        # 从数据库查询（分页）
        logger.info(f"Querying books for list {list_id} from database - page: {page}, page_size: {page_size}")
        
        # 查询总数
        total_count = LkBookListBook.objects(listId=list_id).count()
        
        # 分页查询
        skip = (page - 1) * page_size
        books = LkBookListBook.objects(listId=list_id).order_by('-addedAt').skip(skip).limit(page_size)
        books_data = [book.get_book_info() for book in books]
        
        return returnData(200, '查询成功', {
            "listId": list_id,
            "page": page,
            "page_size": page_size,
            "total": total_count,
            "count": len(books_data),
            "hasMore": skip + page_size < total_count,
            "books": books_data
        })


@router.post("/sync_all_lists/")
async def sync_all_booklists(
    sort_order: str = Query("CREATED_DESC", description="排序方式"),
    max_pages: int = Query(0, ge=0, description="最大页数,0表示不限制"),
    category: Optional[str] = Query(None, description="分类筛选: female/male")
):
    """
    自动同步所有书单到数据库(按 CREATED_DESC 排序)
    
    参数:
        - sort_order: 排序方式 (CREATED_DESC/DEFAULT/HOT/NEW)
        - max_pages: 最大同步页数,0表示同步所有页
        - category: 分类筛选 (female/male, 可选)
    
    说明:
        会自动分页获取,直到 hasMore=false 或达到 max_pages
    """
    logger.info(f"Starting auto sync all booklists with sort_order: {sort_order}, category: {category}")
    
    total_saved = 0
    page = 1
    page_size = 20
    
    while True:
        logger.info(f"Syncing page {page}" + (f"/{max_pages}" if max_pages > 0 else ""))
        
        # 随机延迟
        await asyncio.sleep(random.uniform(1, 2))
        
        # 获取书单列表
        book_lists_data, has_more, total = await fetch_lk_booklists_from_api(
            page=page,
            page_size=page_size,
            sort_order=sort_order,
            category=category
        )
        
        if not book_lists_data:
            logger.info(f"No more data at page {page}")
            break
        
        # 保存到数据库
        saved_count = save_booklists_to_db(book_lists_data)
        total_saved += saved_count
        
        logger.info(f"Page {page}: saved {saved_count} booklists (total: {total_saved})")
        
        # 检查是否继续
        if not has_more:
            logger.info("No more pages (hasMore=false)")
            break
        
        # 检查是否达到最大页数
        if max_pages > 0 and page >= max_pages:
            logger.info(f"Reached max_pages limit: {max_pages}")
            break
        
        page += 1
    
    return returnData(200, '同步完成', {
        "total_pages": page,
        "total_saved": total_saved,
        "sort_order": sort_order,
        "category": category
    })


@router.post("/sync_books_by_ranges/")
async def sync_booklist_books_by_ranges(
    ranges: str = Query(..., description="书籍数量分档，格式: 200-20000,100-200,50-100,20-50,0-20"),
    max_lists_per_range: int = Query(50, ge=1, description="每个分档最多处理的书单数")
):
    """
    按书籍数量分档从数据库查询书单，并从 API 入库每个书单的所有书籍
    
    参数:
        - ranges: 书籍数量分档，逗号分隔，例: "200-20000,100-200,50-100,20-50,0-20"
        - max_lists_per_range: 每个分档最多处理的书单数
        
    说明:
        1. 按照分档范围从数据库查询符合条件的书单
        2. 逐个书单从 API 获取其所有书籍并入库到 lk_book_list_book 表
    """
    try:
        # 解析分档范围
        range_list = []
        for r in ranges.split(','):
            r = r.strip()
            if '-' in r:
                min_val, max_val = r.split('-')
                range_list.append((int(min_val), int(max_val)))
        
        if not range_list:
            return returnData(400, '无效的分档范围', None)
        
        logger.info(f"开始按分档入库书单书籍: {range_list}")
        
        total_lists_processed = 0
        total_books_saved = 0
        range_results = []
        
        # 逐个分档处理
        for min_books, max_books in range_list:
            logger.info(f"\n========== 处理分档: {min_books}-{max_books} ==========")
            
            # 从数据库查询符合条件的书单
            query = Q(bookCount__gte=min_books) & Q(bookCount__lte=max_books)
            book_lists = LkBookList.objects(query).limit(max_lists_per_range)
            
            range_list_count = book_lists.count()
            logger.info(f"找到 {range_list_count} 个符合条件的书单，处理前 {max_lists_per_range} 个")
            
            range_books_saved = 0
            range_lists_processed = 0
            
            # 逐个书单处理
            for book_list in book_lists:
                list_id = book_list.listId
                list_title = book_list.title
                book_count = book_list.bookCount
                
                logger.info(f"\n--- 处理书单: {list_id} - {list_title} ({book_count}本) ---")
                
                # 获取该书单的所有书籍（自动分页）
                page = 1
                list_books_saved = 0
                fetched_count = 0
                page_size = 20
                
                while True:
                    # 随机延迟，防止被封
                    await asyncio.sleep(random.uniform(1, 3))
                    
                    logger.info(f"  获取第 {page} 页...")
                    books_data, api_book_count, _ = await fetch_booklist_books_from_api(list_id, page)
                    
                    # 第一页时更新总书籍数
                    if page == 1 and api_book_count > 0:
                        book_count = api_book_count
                        logger.info(f"  API 返回总书籍数: {book_count}")
                    
                    if not books_data:
                        if page == 1:
                            logger.warning(f"  书单 {list_id} 没有数据或需要登录")
                        break
                    
                    # 入库
                    saved_count = save_booklist_books_to_db(list_id, books_data)
                    list_books_saved += saved_count
                    fetched_count += len(books_data)
                    logger.info(f"  第 {page} 页: 入库 {saved_count} 本")
                    
                    # 判断是否还有下一页
                    if fetched_count >= book_count or len(books_data) < page_size:
                        logger.info(f"  已获取所有书籍 ({fetched_count}/{book_count})")
                        break
                    
                    page += 1
                
                range_books_saved += list_books_saved
                range_lists_processed += 1
                logger.info(f"--- 书单 {list_id} 完成: 共入库 {list_books_saved} 本书 ---")
            
            # 记录本分档结果
            range_results.append({
                "range": f"{min_books}-{max_books}",
                "lists_in_db": range_list_count,
                "lists_processed": range_lists_processed,
                "books_saved": range_books_saved
            })
            
            total_lists_processed += range_lists_processed
            total_books_saved += range_books_saved
            
            logger.info(f"\n分档 [{min_books}-{max_books}] 完成: 处理 {range_lists_processed} 个书单, 入库 {range_books_saved} 本书")
        
        logger.info(f"\n========== 所有分档处理完成 ==========")
        logger.info(f"总处理书单: {total_lists_processed}, 总入库书籍: {total_books_saved}")
        
        return returnData(200, '分档入库书籍完成', {
            "total_lists_processed": total_lists_processed,
            "total_books_saved": total_books_saved,
            "range_results": range_results
        })
        
    except Exception as e:
        logger.error(f"分档入库书籍失败: {str(e)}")
        return returnData(500, f"失败: {str(e)}", None)


@router.get("/stats/")
async def get_booklist_stats(
    min_books: int = Query(None, description="最小书籍数（包含）"),
    max_books: int = Query(None, description="最大书籍数（包含）")
):
    """
    统计书单信息
    
    参数:
        - min_books: 最小书籍数（包含），不传则不限制
        - max_books: 最大书籍数（包含），不传则不限制
        
    示例:
        - min_books=20: 查询 >= 20 本的书单
        - max_books=19: 查询 <= 19 本的书单
        - min_books=10&max_books=30: 查询 10-30 本的书单
        
    返回:
        - total_lists: 书单总数
        - total_books: 书单中声明的书籍总数
    """
    try:
        # 构建查询条件
        query = Q()
        query_desc_parts = []
        
        if min_books is not None:
            query &= Q(bookCount__gte=min_books)
            query_desc_parts.append(f"书籍数>={min_books}")
        
        if max_books is not None:
            query &= Q(bookCount__lte=max_books)
            query_desc_parts.append(f"书籍数<={max_books}")
        
        query_description = " 且 ".join(query_desc_parts) if query_desc_parts else "所有书单"
        logger.info(f"查询条件: {query_description}")
        
        # 查询符合条件的书单
        book_lists = LkBookList.objects(query)
        
        # 统计数据
        total_lists = book_lists.count()  # 书单总数
        total_books = sum(book_list.bookCount or 0 for book_list in book_lists)  # 书籍总数
        
        logger.info(f"统计完成: 书单数={total_lists}, 书籍总数={total_books}")
        
        return returnData(200, '统计成功', {
            "query_description": query_description,
            "total_lists": total_lists,  # 书单总数
            "total_books": total_books  # 书籍总数（从书单表的bookCount字段统计）
        })
        
    except Exception as e:
        logger.error(f"统计出错: {str(e)}")
        return returnData(500, f"统计失败: {str(e)}", None)


@router.post("/sync_books_from_db/")
async def sync_booklist_books_from_db(
    start_page: int = Query(1, gt=0, description="起始页码"),
    end_page: int = Query(10, gt=0, description="结束页码"),
    page_size: int = Query(20, gt=0, le=100, description="每页数量")
):
    """
    批量从本地数据库的书单表逅历,获取每个书单的书籍详情
    
    参数:
        - start_page: 起始页码 (例如: 1)
        - end_page: 结束页码 (例如: 10)
        - page_size: 每页查询的书单数量
    """
    if end_page < start_page:
        return returnData(400, '结束页不能小于起始页', None)
    
    total_synced = 0
    total_books_saved = 0
    
    for page in range(start_page, end_page + 1):
        logger.info(f"Syncing books for page {page}/{end_page}")
        
        # 从数据库分页查询书单
        skip = (page - 1) * page_size
        book_lists = LkBookList.objects().order_by('-lastActiveAt').skip(skip).limit(page_size)
        
        if not book_lists:
            logger.info(f"No more book lists at page {page}")
            break
        
        for book_list in book_lists:
            list_id = book_list.listId
            total_book_count = book_list.bookCount  # 从数据库获取总书籍数
            logger.info(f"Fetching books for list: {list_id} - {book_list.title} ({total_book_count} books)")
            
            # 获取该书单的所有页(自动分页)
            list_saved_count = 0
            fetched_count = 0
            page = 1
            page_size = 20
            
            while True:
                # 随机延迟,防止被封
                await asyncio.sleep(random.uniform(1, 3))
                
                logger.info(f"  Fetching page {page} for list {list_id}")
                books_data, api_book_count, _ = await fetch_booklist_books_from_api(list_id, page)
                
                # 第一页时更新总书籍数
                if page == 1 and api_book_count > 0:
                    total_book_count = api_book_count
                    logger.info(f"  Updated book count from API: {total_book_count}")
                
                if not books_data:
                    if page == 1:
                        logger.warning(f"List {list_id}: no books data or need login")
                    break
                
                saved_count = save_booklist_books_to_db(list_id, books_data)
                list_saved_count += saved_count
                fetched_count += len(books_data)
                logger.info(f"  Page {page}: saved {saved_count} books")
                
                # 根据总数和当前页数据量判断是否还有下一页
                if fetched_count >= total_book_count or len(books_data) < page_size:
                    logger.info(f"  Fetched all books ({fetched_count}/{total_book_count})")
                    break
                
                page += 1
            
            if list_saved_count > 0:
                total_books_saved += list_saved_count
                total_synced += 1
                logger.info(f"List {list_id}: total saved {list_saved_count} books from {page} pages")
    
    return returnData(200, '同步完成', {
        "synced_lists": total_synced,
        "total_books_saved": total_books_saved
    })
